#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <poll.h>
#include "Socket.hpp"
#include "Logger.hpp"
#include "InetAddr.hpp"

const static int gsize = sizeof(fd_set) * 8;
const static int gdefault = -1;

class PollServer
{
public:
    PollServer(uint16_t port)
        : _listensock(std::make_unique<TcpSocket>(port))
    {
        // 建立listen套接字
        _listensock->BuildListenSocketMethod(port);
        // 初始化数组
        for (int i = 0; i < gsize; i++)
        {
            array[i].fd = gdefault;
            array[i].events = array[i].revents = 0;
        }
        array[0].fd = _listensock->Sockfd();
        array[0].events = POLLIN;
    }
    void Accepter()
    {
        InetAddr clientaddr;
        int sockfd = _listensock->AcceptSocketOrDie(&clientaddr);
        if (sockfd > 0)
        {
            // 这里不能直接recv，而是要连接的套接字托管给select
            // 我们在创建的数组中标记出连接的sockfd对应的数组下标位置
            int pos = 0;
            for (; pos < gsize; pos++)
            {
                if (array[pos].fd = gdefault)
                {
                    array[pos].fd = sockfd;
                    array[pos].events = POLLIN;
                    break;
                }
            }
            // 这里说明服务器满了
            if (pos == gsize)
            {
                LOG(LogLevel::WARNING) << "server is full!";
                close(sockfd);
            }
        }
    }
    void Recver(int index)
    {
        int sockfd = array[index].fd;
        char buffer[1024];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer), 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "client say@ " << buffer << std::endl;
            std::string echo_string = "server echo# ";
            echo_string += buffer;
            send(sockfd, echo_string.c_str(), echo_string.size(), 0);
        }
        else if (n == 0)
        {
            LOG(LogLevel::INFO) << "client quit, me too: " << array[index].fd;
            array[index].fd = gdefault;
            array[index].events = array[index].revents = 0;
            close(sockfd);
        }
        else
        {
            LOG(LogLevel::WARNING) << "recv error: " << array[index].fd;
            array[index].fd = gdefault;
            array[index].events = array[index].revents = 0;
            close(sockfd);
        }
    }
    void EventDispatcher()
    {
        // 这里一定是有新的事件到来
        LOG(LogLevel::INFO) << "have new work.....";
        for (int i = 0; i < gsize; i++)
        {
            if (array[i].fd == gdefault)
                continue;
            //读事件就绪
            if (array[i].events & POLLIN)
            {
                if (array[i].fd == _listensock->Sockfd())
                {
                    // 连接管理
                    Accepter();
                }
                else
                {
                    // 读事件处理器
                    Recver(i);
                }
            }
        }
    }

    void Run()
    {
        while (true)
        {
            int timeout = -1;
            int n = poll(array, gsize, timeout);
            if (n == 0)
            {
                LOG(LogLevel::INFO) << "time......";
                break;
            }
            else if (n < 0)
            {
                LOG(LogLevel::WARNING) << "select error!";
                break;
            }
            else
            {
                EventDispatcher();
            }
        }
    }
    ~PollServer()
    {
    }

private:
    std::unique_ptr<Socket> _listensock;
    struct pollfd array[gsize];
};